﻿using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Text;
using System;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Net.Sockets;
using System.Net.NetworkInformation;
using System.Data.SqlClient;
using System.Linq;
using System.Collections.Specialized;
using Core.Contracts.Enums;

namespace CsvParser
{
    /// <summary>
    /// 
    /// </summary>
    /// <remarks></remarks>
    class Program
    {
        #region KEYS

        private static readonly string[] ammosHeaders = new string[]
        {
            "Group",
            "Size",
            "Type",
            "Name",
            "Mass",
            "Volume",
            "KineticDamage",
            "SeismicDamage",
            "ChemicalDamage",
            "ThermalDamage",
            "OptimalRangeModifier",
            "FalloffModifier",
            "AddedEnergy",
            "RadiusOfScannedArea",
            "ScannedAreaRadius",
            "TotalOperationalTime",
            "Armor",
            "SurfaceHitSize",
            "InterferenceEmission",
            "InterferenceRadius",
            "ExplosionSize",
            "OptimalRange",
        };

        static readonly string[] modulesHeaders = new string[]{
		"MetaGroup",
		"Group",
        "ModuleClass",
		"Size",
        "Module",
		"CpuUsage",
		"ReactorUsage",
		"ActiveChemicalResistance",
		"PassiveChemicalResistance",
		"Type",
		"Slot",
		"TechnologicalLevel",
		"Mass",
		"PackedVolume",
		"Volume",
		"AccumulatorConsumption",
		"CycleTime",
		"ActiveKineticResistance",
		"PassiveKineticResistance",
		"ActiveSeismicResistance",
		"PassiveSeismicResistance",
		"ActiveThermalResistance",
		"PassiveThermalResistance",
		"Armor",
		"DemobilizerResistance",
		"Repair",
		"ArmorRepairAccumulatorUsage",
		"ArmorRepairAmount",
		"ArmorRepairCycleTime",
		"RemoteArmorRepairAccumulatorUsage",
		"ArmorHitPoints",
		"OptimalRange",
		"Falloff",
		"CpuPerformance",
		"OptimalRangeModifier",
		"LockingRange",
		"LockingTime",
		"SignalDetectionModification",
		"SignalMaskingModification",
		"TopSpeedModification",
		"PassiveSensorStrengthModification",
		"EwStrength",
		"AmmoChargeType",
		"AmmoChargeCapacity",
		"InterferenceEmitterRadiusModification",
		"InterferenceEmitterStrengthModification",
		"AccumulatorRechargeTime",
		"AccumulatorCapacity",
		"ReactorPerformance",
		"DrainedEnergy",
		"ElectrostaticDispersion",
		"NeutralizedEnergy",
		"TransferedEnergy",
		"ChemicalDamageRecovery",
		"KineticDamageRecovery",
		"SeismicDamageRecovery",
		"ThermalDamageRecovery",
		"SurfaceHitSize",
		"GeoscannerAccuracy",
		"HarvestedAmountIncrease",
		"MinedAmountIncrease",
		"ArmorModification",
		"DefaultEffectRadius",
		"EffectRangeModification",
		"WeaponCycleTime",
		"CriticalHitChanceModification",
		"SurfaceHitSizeModification",
		"EwModuleOptimalRange",
		"LockingRangeModification",
		"IndustrialModuleCycleTime",
		"IndustrialModuleAccumulatorUsage",
		"LockingTimeModification",
		"AccumulatorRechargeTimeModification",
		"ArmorRepairAmountModification",
		"ShieldAbsorptionModification",
		"AbsorptionRatio",
		"ShieldRadius",
		"ShieldAbsorption",
		"Damage",
		"HitDispersion",
		"MissileOptimalRangeModification",
		"MissileLauncherCycleTime",
		"CriticalHitChance",
		"ExplosionSize",
        "SensorStrength" };
        
        #endregion

        #region ModuleClass

        private const string MODULE_CLASS = @" 
namespace Core.Items.Modules
{
    /*
<HEADER>
    */

    using System;
    using Base;
    using Contracts.Enums;
    using Contracts.Interfaces;
    using Extensions;
    using Features;
    
    /// <summary>
    /// <MODULENAMELONG> module class
    /// </summary>
    /// <remarks>File generated on <DATE></remarks>
    public sealed class <MODULENAME> : ModuleBase
    {
        /// <summary>
        /// Create a new instance of the <see cref=""<MODULENAME>""/> class.
        /// </summary>
        public <MODULENAME>()
            : base(
            ""<MODULENAMELONG>"",
            """",
            ModuleMetaGroupsEnum.<METAGROUP>,
            ModuleGroupsEnum.<GROUP>,
            TechnologyLevelsEnum.<TECH>,
            SizesEnum.<SIZE>,
            new LazyFeature[] { <FEATURES> },
            null,
            new IModifier[] { <MODIFIERS> } )
        {
        }

        /// <summary>
        /// Obtains the activation type
        /// </summary>
        public override ModuleActivationTypesEnum ActivationType
        {
            get { return ModuleActivationTypesEnum.<ACTIVATION>; }
        }
        /// <summary>
        /// Obtains the module slot group 
        /// </summary>
        public override SlotGroupsEnum SlotGroup
        {
            get { return SlotGroupsEnum.<SLOTGROUP>; }
        }
        /// <summary>
        /// Obtains the module slot type 
        /// </summary>
        public override SlotTypesEnum SlotType
        {
            get { return SlotTypesEnum.<SLOTTYPE>; }
        }
    }
}";


        #endregion

        #region Ammo class

        private const string AMMO_CLASS = @"
namespace Core.Items.Ammunitions
{
    /* 
<HEADER>
    */

    using System;
    using Base;
    using Contracts.Enums;
    using Contracts.Interfaces;
    using Features;

    /// <summary>
    /// <AMMO> ammunition class
    /// </summary>
    /// <remarks>File generated on <DATE></remarks>
    public class <CLASS> : AmmunitionBase
    {
        /// <summary>
        /// Create a new instance of the <see cref=""T:Core.Items.Ammunitions.<CLASS>""/> class.
        /// </summary>
        public <CLASS>() : base(
            ""<AMMO>"",
            """",
            AmmunitionSizesEnum.<SIZE>,
            AmmunitionGroupesEnum.<GROUP>,
            AmmunitionTypesEnum.<TYPE>,
            new LazyFeature[]{ <FEATURES> },
            new IModifier[]{ <MODIFIERS> }
            )
        {
        }
    }
}";

        #endregion

        const string TOP_DIR = @"C:\Games\Perpetuum\CSV";
        const string GEN_MOD_DIR = "..\\..\\..\\..\\Core\\Items\\Modules";
        const string GEN_AMMO_DIR = "..\\..\\..\\..\\Core\\Items\\Ammunitions";

        const string OFFSET = "\r\n\t\t\t\t";

        private static Dictionary<string, string> _descriptions;

        static void Main(string[] args)
        {
            _descriptions = new Dictionary<string, string>();
            ParseDescriptions(".\\dictionary.txt", _descriptions);

            //ParseAmmoCsvFiles(TOP_DIR);
            //ParseAmmo(".\\Ammunitions.csv", GEN_AMMO_DIR);

            //ParseModulesCsvFiles(TOP_DIR);
            ParseModules(".\\modules.csv", GEN_MOD_DIR);
        }

        static void ParseDescriptions(string file, Dictionary<string, string> dictionary)
        {
            var content = File.ReadAllText(file);

            var matches = Regex.Matches(content, @"(?:\|)(?<key>.*)(?:\=\$)(?<value>.*)");
            for(int i=0; i< matches.Count; i++)
            {
                var key = matches[i].Groups["key"].Value;
                var value = matches[i].Groups["value"].Value;

                if(!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
                    dictionary.Add(key, value.Replace(@"\23","#"));
            }

        }

        static void ParseModules(string file, string outdir)
        {
            if(string.IsNullOrEmpty(file) || string.IsNullOrEmpty(outdir)) return;

            if (!Directory.Exists(outdir))
                Directory.CreateDirectory(outdir);

            var classBuilder = new StringBuilder();
            var featuresBuilder = new StringBuilder();
            var modifiersBuilder = new StringBuilder();
            var headerBuilder = new StringBuilder();

            // Initializing xml modules file tree
            var xmlTreeBuilder = new StringBuilder();
            xmlTreeBuilder.Append("<?xml version=\"1.0\" encoding=\"utf-8\"?><modules>");
            
            string lastMetagroup = null;
            string lastGroup = null;
            string lastClass = null;
            string lastSize = null;

            // reading csv file content
            var lines = File.ReadAllLines(file, Encoding.UTF8);

            int replacedcount = 0;
            int itemsCount = 0;

            for(int l = 1; l < lines.Length; l++ ) // skiping header line
            {
                if(string.IsNullOrEmpty(lines[l])) continue;

                itemsCount++;

                classBuilder.Clear();
                featuresBuilder.Clear();
                modifiersBuilder.Clear();
                headerBuilder.Clear();

                string moduleMetagroup = null;
                string moduleGroup = null;
                string moduleClass = null;
                string moduleSize = null;
                string moduleName = null;
                string moduleDescription = null;
                string techLevel = null;
                string activation = null;
                string slotGroup = null;
                string slotType = null;

                // Generating file header
                var values = lines[l].Split(';');
                for(int i=0; i< values.Length; i++)
                {
                    if(string.IsNullOrEmpty(values[i])) continue;
                    headerBuilder.AppendFormat("\r\n\t\t{0,-30} = {1}", modulesHeaders[i], values[i]);
                }
                
                int index;

                index = Array.IndexOf(modulesHeaders, "MetaGroup");
                if(index != -1 && !string.IsNullOrEmpty(values[index]))
                    moduleMetagroup = values[index]
                        .Replace("IndustrialModules", "Industrial");

                index = Array.IndexOf(modulesHeaders, "Group");
                if (index != -1 && !string.IsNullOrEmpty(values[index]))
                {
                    moduleGroup = values[index]
                        .Replace("HarversterModules", "HarvesterModules");

                    if (string.Equals("NexusModules", moduleMetagroup))
                        moduleGroup = moduleGroup
                            .Replace("Armor", "NexusModuleArmor")
                            .Replace("Assault", "NexusModuleAssault")
                            .Replace("CriticalHit", "NexusModuleCriticalHit")
                            .Replace("Evasive", "NexusModuleEvasive")
                            .Replace("Ew", "NexusModuleEw")
                            .Replace("Farlock", "NexusModuleFarlock")
                            .Replace("FastExtractor", "NexusModuleFastExtractor")
                            .Replace("Industrial", "NexusModuleIndustrial")
                            .Replace("LockBooster", "NexusModuleLockBooster")
                            .Replace("Recharger", "NexusModuleRecharger")
                            .Replace("Repairer", "NexusModuleRepairer")
                            .Replace("Shield", "NexusModuleShield")
                            .Replace("Velocity", "NexusModuleVelocity");
                }

                index = Array.IndexOf(modulesHeaders, "ModuleClass");
                if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    moduleClass = values[index];

                index = Array.IndexOf(modulesHeaders, "Size");
                if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    moduleSize = values[index];

                index = Array.IndexOf(modulesHeaders, "Module");
                if (index != -1 && !string.IsNullOrEmpty(values[index]))
                {
                    string temp = values[index]
                        .Replace(" ii ", " II. ")
                        .Replace(" i ", " I. ")
                        .Replace("-ii ", "-II ")
                        .Replace("-i ", "-I ")
                        .Replace(" ix ", " IX ")
                        .Replace(" iy ", " IY ")
                        .Replace("msd m 15 filch", "MSD m#15 'Filch'")
                        .Replace("-fbp-II", "-fbp-II.")
                        .Replace("5 5-glipler", "5.5-glipler")
                        .Replace("5s hastex", ".5s Hastex")
                        .Replace("fo-150 reparator", "FO-150 'Reparator'")
                        .Replace("quissot s", "Quissot's")
                        .Replace("unotron 60s- crack shot", "Unotron 60s-'Crack shot'")
                        .Replace("rogue signal detector", "'Rogue' signal detector")
                        .Replace("nnt IX s-demobilizer", "NNt. IX S-demobilizer")
                        .Replace("nnt IY s-demobilizer", "NNt. IY S-demobilizer")
                        .Replace("duobar 300xs- othys", "Duobar 300xs-'Othys'")
                        .Replace("y-type connector", "Y-type 'Connector'")
                        .Replace("ser-250 eruptico", "SER-250 'Eruptico'")
                        .Replace("ser-300 devactico", "SER-300 'Devactico'")
                        .Replace("mha 900- sap", "MHA 900-'Sap'")
                        .Replace("mha 400- avalon", "MHA 400-'Avalon'")
                        .Replace("mma v12- alkhemir", "MMA v12-'Alkhemir'")
                        .Replace("scorch assault", "'Scorch' assault");

                    moduleDescription = temp.Trim(); 
                    bool found = false;
                    var dicEnu = _descriptions.GetEnumerator();
                    while (dicEnu.MoveNext())
                    {
                        if(string.Equals(dicEnu.Current.Value, moduleDescription, StringComparison.InvariantCultureIgnoreCase))
                        {
                            moduleDescription = dicEnu.Current.Value;
                            replacedcount++;
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                        Debug.WriteLine("No description translation found for module : " + moduleDescription);

                    // remove invalid chars for a c# class name
                    temp = temp.Replace("#", "").Replace(".", "").Replace("'", "").Replace("-", " ").TrimStart();

                    // remove numbers from starting position
                    while (char.IsNumber(temp.ToCharArray()[0]) || char.IsWhiteSpace(temp.ToCharArray()[0]))
                        temp = temp.Substring(1);

                    moduleName = NormalizeString(temp);
                }

                index = Array.IndexOf(modulesHeaders, "TechnologicalLevel");
                if (index != -1 && !string.IsNullOrEmpty(values[index]))
                {
                    techLevel = values[index];
                    switch (techLevel)
                    {
                        case "S":   techLevel = "Standard"; break;
                        case "T0":  techLevel = "Level0"; break;
                        case "T1":  techLevel = "Level1"; break;
                        case "T2":  techLevel = "Level2"; break;
                        case "T3":  techLevel = "Level3"; break;
                        case "T3-": techLevel = "Niani"; break;
                        case "T4":  techLevel = "Level4"; break;
                        case "T1P": techLevel = "Level1|TechnologyLevelsEnum.Prototype"; break;
                        case "T2P": techLevel = "Level2|TechnologyLevelsEnum.Prototype"; break;
                        case "T3P": techLevel = "Level3|TechnologyLevelsEnum.Prototype"; break;
                        case "T4P": techLevel = "Level4|TechnologyLevelsEnum.Prototype"; break;
                        case "T4+": techLevel = "Level4|TechnologyLevelsEnum.Elite"; break;
                        case "T2+": techLevel = "Level2|TechnologyLevelsEnum.Elite"; break;

                    }
                }

                index = Array.IndexOf(modulesHeaders, "Type");
                if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    activation =  values[index];

                index = Array.IndexOf(modulesHeaders, "Slot");
                if (index != -1 && !string.IsNullOrEmpty(values[index]))
                {
                    switch (values[index])
                    {
                        case "Head":
                            slotGroup = "Head";
                            slotType = "Modules";
                            break;
                        case "Legs":
                            slotGroup = "Legs";
                            slotType = "Modules";
                            break;
                        case "Industrial":
                            slotGroup = "Chassis";
                            slotType = "Industrial";
                            break;
                        case "Missile":
                            slotGroup = "Chassis";
                            slotType = "Missile";
                            break;
                        case "Other":
                            slotGroup = "Chassis";
                            slotType = "Misc";
                            break;
                        case "Turret":
                            slotGroup = "Chassis";
                            slotType = "Turret";
                            break;
                    }
                }

                #region XML modules tree

                if (!string.Equals(lastSize, moduleSize))
                {
                    if (!string.IsNullOrEmpty(lastSize))
                        xmlTreeBuilder.AppendFormat("</{0}>", lastSize);
                }
                if (!string.Equals(lastClass, moduleClass))
                {
                    if(!string.IsNullOrEmpty(lastClass))
                        xmlTreeBuilder.AppendFormat("</{0}>", lastClass);
                }
                if (!string.Equals(lastGroup, moduleGroup))
                {
                    if (!string.IsNullOrEmpty(lastGroup))
                        xmlTreeBuilder.AppendFormat("</{0}>", lastGroup);
                }
                if (!string.Equals(lastMetagroup, moduleMetagroup))
                {
                    if (!string.IsNullOrEmpty(lastMetagroup))
                        xmlTreeBuilder.AppendFormat("</{0}>", lastMetagroup);
                }

                if (!string.IsNullOrEmpty(moduleMetagroup) && !string.Equals(lastMetagroup, moduleMetagroup))
                    xmlTreeBuilder.AppendFormat("<{0}>", moduleMetagroup);

                if (!string.IsNullOrEmpty(moduleGroup) && !string.Equals(lastGroup, moduleGroup))
                    xmlTreeBuilder.AppendFormat("<{0}>", moduleGroup);

                if (!string.IsNullOrEmpty(moduleClass) && !string.Equals(lastClass, moduleClass))
                    xmlTreeBuilder.AppendFormat("<{0}>", moduleClass);

                if (!string.IsNullOrEmpty(moduleSize) && !string.Equals(lastSize, moduleSize))
                    xmlTreeBuilder.AppendFormat("<{0}>", moduleSize);

                xmlTreeBuilder.AppendFormat("<module type=\"{1}\">{0}</module>",moduleDescription,moduleName);
                
                lastMetagroup = moduleMetagroup;
                lastGroup = moduleGroup;
                lastClass = moduleClass;
                lastSize = moduleSize;

                #endregion

                Debug.Assert(!string.IsNullOrEmpty(moduleName));

                if (string.IsNullOrEmpty(moduleMetagroup))
                {
                }

                #region Armor
                #region Armor Harderners
                else if (string.Equals("Armor", moduleMetagroup) && string.Equals("ArmorHardeners", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ArmorModuleCpuUsage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ArmorModuleReactorUsage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CycleTime<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "ActiveChemicalResistance");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        //value = value.Substring(0, value.IndexOf("(")).Trim();

                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.ChemicalResistance, {1}){{ ActivationState = ModuleActivationTypesEnum.Active, Unit = UnitsEnum.Points, DisplayName = \"Chemical resistance\"  }},", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "PassiveChemicalResistance");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        //value = value.Substring(0, value.IndexOf("(")).Trim();

                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, 
                            "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.ChemicalResistance, {1}){{ {2} Unit = UnitsEnum.Points, DisplayName = \"Chemical resistance\"  }},", OFFSET, value, activation == "Active" ? "ActivationState = ModuleActivationTypesEnum.Passive," : null );
                    }

                    index = Array.IndexOf(modulesHeaders, "ActiveKineticResistance");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        //value = value.Substring(0, value.IndexOf("(")).Trim();

                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.KineticResistance, {1}){{ ActivationState = ModuleActivationTypesEnum.Active, Unit = UnitsEnum.Points, DisplayName = \"Kinetic resistance\"  }},", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "PassiveKineticResistance");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        //value = value.Substring(0, value.IndexOf("(")).Trim();

                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.KineticResistance, {1}){{ {2} Unit = UnitsEnum.Points, DisplayName = \"Kinetic resistance\"  }},", OFFSET, value, activation == "Active" ? "ActivationState = ModuleActivationTypesEnum.Passive," : null);
                    }

                    index = Array.IndexOf(modulesHeaders, "ActiveSeismicResistance");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        //value = value.Substring(0, value.IndexOf("(")).Trim();

                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.SeismicResistance, {1}){{ ActivationState = ModuleActivationTypesEnum.Active, Unit = UnitsEnum.Points, DisplayName = \"Seismic resistance\"  }},", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "PassiveSeismicResistance");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        //value = value.Substring(0, value.IndexOf("(")).Trim();

                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.SeismicResistance, {1}){{ {2} Unit = UnitsEnum.Points, DisplayName = \"Seismic resistance\"  }},", OFFSET, value, activation == "Active" ? "ActivationState = ModuleActivationTypesEnum.Passive," : null);
                    }

                    index = Array.IndexOf(modulesHeaders, "ActiveThermalResistance");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        //value = value.Substring(0, value.IndexOf("(")).Trim();

                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.ThermalResistance, {1}){{ ActivationState = ModuleActivationTypesEnum.Active, Unit = UnitsEnum.Points, DisplayName = \"Thermal resistance\"  }},", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "PassiveThermalResistance");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        //value = value.Substring(0, value.IndexOf("(")).Trim();

                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.ThermalResistance, {1}){{ {2} Unit = UnitsEnum.Points, DisplayName = \"Thermal resistance\"  }},", OFFSET, value, activation == "Active" ? "ActivationState = ModuleActivationTypesEnum.Passive," : null);
                    }


                }

                #endregion
                #region Armor Plates
                else if (string.Equals("Armor", moduleMetagroup) && string.Equals("ArmorPlates", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ArmorModuleCpuUsage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ArmorModuleReactorUsage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "Armor");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.ArmorAmount, {1} ){{ Unit = UnitsEnum.Hitpoints, DisplayName = \"Armor amount\" }},", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "SurfaceHitSize");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.SurfaceHitSize, {1} ){{ Unit = UnitsEnum.Meters, DisplayName = \"Surface Hit Size\" }},", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "DemobilizerResistance");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;

                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.DemobilizerResistance, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Demobilizer resistance\" }},", OFFSET, percent);
                    }

                }
                #endregion
                #region Armor Repairers
                else if (string.Equals("Armor", moduleMetagroup) && string.Equals("ArmorRepairers", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ArmorModuleCpuUsage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ArmorModuleReactorUsage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ArmorRepairAccumulatorUsage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ArmorRepairCycleTime<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "Repair");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ArmorRepairAmount<double>),{1}),", OFFSET, value);
                    }

                }
                #endregion
                #region Armor Repairers Tunings
                else if (string.Equals("Armor", moduleMetagroup) && string.Equals("ArmorRepairersTunings", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ArmorModuleCpuUsage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ArmorModuleReactorUsage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "ArmorRepairAccumulatorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.ArmorRepairAccumulatorUsage, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Repairer accumulator usage\"  }},", OFFSET, percent);
                    }

                    index = Array.IndexOf(modulesHeaders, "ArmorRepairAmount");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.ArmorRepairAmount, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Repair amount\"  }},", OFFSET, percent);
                    }

                    index = Array.IndexOf(modulesHeaders, "ArmorRepairCycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.ArmorRepairCycleTime, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Repair cycle time\"  }},", OFFSET, percent);
                    }

                    index = Array.IndexOf(modulesHeaders, "RemoteArmorRepairAccumulatorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.RemoteArmorRepairAccumulatorUsage, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Remote repairer accumulator usage\"  }},", OFFSET, percent);
                    }

                }
                #endregion
                #region Lightweight Frames
                else if (string.Equals("Armor", moduleMetagroup) && string.Equals("LightweightFrames", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        // Data not present in csv export but needed for calculation!! doh!
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, 2);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, 2);
                        
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Robot mass\"  }},", OFFSET, percent);
                    }

                    index = Array.IndexOf(modulesHeaders, "DemobilizerResistance");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.DemobilizerResistance, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Demobilizer resistance\"  }},", OFFSET, percent);
                    }

                    index = Array.IndexOf(modulesHeaders, "ArmorHitPoints");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.ArmorAmount, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Armor amount\"  }},", OFFSET, percent);
                    }

                }
                #endregion
                #region Remote Armor Repairers
                else if (string.Equals("Armor", moduleMetagroup) && string.Equals("RemoteArmorRepairers", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ArmorModuleCpuUsage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ArmorModuleReactorUsage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(RemoteArmorRepairAccumulatorUsage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(RemoteArmorRepairCycleTime<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "Repair");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(RemoteArmorRepairAmount<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "OptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(RemoteArmorRepairOptimal<double>),{1}),", OFFSET, value);
                    }

                }
                #endregion
                #endregion

                #region Electronic Equipment
                #region Cargo Scanners
                else if (string.Equals("ElectronicEquipment", moduleMetagroup) && string.Equals("CargoScanners", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CargoScannerCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "OptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CargoScannerOptimal<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Falloff");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CargoScannerFalloff<double>),{1}),", OFFSET, value);
                    }

                }
                #endregion
                #region Chassis Scanners
                else if (string.Equals("ElectronicEquipment", moduleMetagroup) && string.Equals("ChassisScanners", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ChassisScannerCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "OptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ChassisScannerOptimal<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Falloff");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ChassisScannerFalloff<double>),{1}),", OFFSET, value);
                    }

                }
                #endregion
                #region Coprocessors
                else if (string.Equals("ElectronicEquipment", moduleMetagroup) && string.Equals("Coprocessors", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CpuPerformance");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.CpuPerformance, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Cpu Performance\" }},", OFFSET, percent);
                    }

                }
                #endregion
                #region Range Extenders
                else if (string.Equals("ElectronicEquipment", moduleMetagroup) && string.Equals("RangeExtenders", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }

                    index = Array.IndexOf(modulesHeaders, "OptimalRangeModifier");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.SmallMagneticWeaponOptimal, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Small Magnetic weapon optimal\" }},", OFFSET, percent);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.MediumMagneticWeaponOptimal, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Medium Magnetic weapon optimal\" }},", OFFSET, percent);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.SmallFirearmOptimal, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Small Firearm optimal\" }},", OFFSET, percent);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.MediumFirearmOptimal, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Medium Firearm optimal\" }},", OFFSET, percent);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.SmallLaserOptimal, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Small Laser optimal\" }},", OFFSET, percent);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.MediumLaserOptimal, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Medium Laser optimal\" }},", OFFSET, percent);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Ammo, FeaturesEnum.MissileOptimal, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Missile optimal\" }},", OFFSET, percent);
                    }

                }
                #endregion
                #region Remote Sensor Amplifiers
                else if (string.Equals("ElectronicEquipment", moduleMetagroup) && string.Equals("RemoteSensorAmplifiers", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(RemoteSensorAmplifierCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "OptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(RemoteSensorAmplifierOptimal<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "LockingRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(RemoteSensorAmplifierLockingRangeBonus<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "LockingTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(RemoteSensorAmplifierLockingTimeBonus<double>),{1}),", OFFSET, percent);
                    }

                }
                #endregion
                #region Sensor Amplifiers
                else if (string.Equals("ElectronicEquipment", moduleMetagroup) && string.Equals("SensorAmplifiers", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(SensorAmplifierCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "LockingRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.LockingRange, {1} ){{ ActivationState = ModuleActivationTypesEnum.Active, Unit = UnitsEnum.Percentage, DisplayName = \"Locking range\"  }},", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "LockingTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.LockingTime, {1} ){{ ActivationState = ModuleActivationTypesEnum.Active, Unit = UnitsEnum.Percentage, DisplayName = \"Locking time\"  }},", OFFSET, percent);
                    }

                }
                #endregion
                #region Signal Detectors
                else if (string.Equals("ElectronicEquipment", moduleMetagroup) && string.Equals("SignalDetectors", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(SignalDetectorCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "SignalDetectionModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.SignalDetection, {1} ){{ ActivationState = ModuleActivationTypesEnum.Active,  Unit = UnitsEnum.Percentage, DisplayName = \"Signal detection\"  }},", OFFSET, percent);
                    }

                }
                #endregion
                #region Signal Maskers
                else if (string.Equals("ElectronicEquipment", moduleMetagroup) && string.Equals("SignalMaskers", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(SignalMaskerCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "SignalMaskingModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.SignalMasking, {1} ){{ ActivationState = ModuleActivationTypesEnum.Active, Unit = UnitsEnum.Percentage, DisplayName = \"Signal masking\"  }},", OFFSET, percent);
                    }

                }
                #endregion
                #region Target Markers
                else if (string.Equals("ElectronicEquipment", moduleMetagroup) && string.Equals("TargetMarkers", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(TargetMarkerCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "OptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(TargetMarkerOptimal<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "SignalMaskingModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(TargetMarkerSignalMasking<double>),{1}),", OFFSET, percent);
                    }
                }
                #endregion
                #endregion

                #region Electronic Warfare
                #region Demobilizers
                else if (string.Equals("ElectronicWarfare", moduleMetagroup) && string.Equals("Demobilizers", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(DemobilizerCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "OptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(DemobilizerOptimal<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "TopSpeedModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(DemobilizerTopSpeed<double>),{1}),", OFFSET, percent);
                    }

                }
                #endregion
                #region ECCMs
                else if (string.Equals("ElectronicWarfare", moduleMetagroup) && string.Equals("Eccms", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(EccmCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "SensorStrength");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.SensorStrength, {1} ){{ DisplayName = \"Sensor strength\" }},", OFFSET, value);
                    }

                }
                #endregion
                #region ECMs
                else if (string.Equals("ElectronicWarfare", moduleMetagroup) && string.Equals("Ecms", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "OptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(EcmOptimal<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(EcmCycleTime<double>),{1}),", OFFSET, value);
                    }
                    // 
                    index = Array.IndexOf(modulesHeaders, "EwStrength");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(EcmStrength<double>),{1}),", OFFSET, value);
                    }

                }
                #endregion
                #region Interference Modules
                else if (string.Equals("ElectronicWarfare", moduleMetagroup) && string.Equals("InterferenceModules", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(InterferenceEmitterCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "OptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(InterferenceEmitterOptimal<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "InterferenceEmitterRadiusModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(InterferenceEmitterRadiusModification<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "InterferenceEmitterStrengthModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(InterferenceEmitterStrengthModification<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "AmmoChargeType");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        //var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AmmunitionType<AmmunitionTypesEnum>),AmmunitionTypesEnum.InterferenceEmitterCharges),", OFFSET);
                    }
                    index = Array.IndexOf(modulesHeaders, "AmmoChargeCapacity");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AmmoCapacity<double>),{1}),", OFFSET, value);
                    }

                }
                #endregion
                #region SAP Hacking Modules
                else if (string.Equals("ElectronicWarfare", moduleMetagroup) && string.Equals("SapHackingModules", moduleGroup))
                {
                    techLevel = "Standard";

                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(SapModuleCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "OptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(SapModuleOptimal<double>),{1}),", OFFSET, value);
                    }

                }
                #endregion
                #region Sensor Suppressors
                else if (string.Equals("ElectronicWarfare", moduleMetagroup) && string.Equals("SensorSuppressors", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(SensorSuppressorCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "OptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(SensorSuppressorOptimal<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "LockingRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(SensorSuppressorLockingRange<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "LockingTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(SensorSuppressorLockingTime<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "EwStrength");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(SensorSuppressorStrength<double>),{1}),", OFFSET, value);
                    }

                }
                #endregion
                #endregion

                #region Engineering Equipment
                #region Accumulator Rechargers
                else if (string.Equals("EngineeringEquipment", moduleMetagroup) && string.Equals("AccumulatorRechargers", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorRechargeTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.AccumulatorRechargeTime, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Accumulator recharge time\"  }},", OFFSET, percent);
                    }

                }
                #endregion
                #region Auxiliary Accumulators
                else if (string.Equals("EngineeringEquipment", moduleMetagroup) && string.Equals("AuxiliaryAccumulators", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorCapacity");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.AccumulatorCapacity, {1} ){{ Unit = UnitsEnum.AccumulatorPoints, DisplayName = \"Accumulator capacity\"  }},", OFFSET, value);
                    }

                }
                #endregion
                #region Coreactors
                else if (string.Equals("EngineeringEquipment", moduleMetagroup) && string.Equals("Coreactors", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorPerformance");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.ReactorPerformance, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Reactor performance\"  }},", OFFSET, percent);
                    }

                }
                #endregion
                #region Energy Drainers
                else if (string.Equals("EngineeringEquipment", moduleMetagroup) && string.Equals("EnergyDrainers", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(EnergyDrainerCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "OptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(EnergyDrainerOptimal<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "DrainedEnergy");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(EnergyDrainerDrainedEnergy<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ElectrostaticDispersion");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(EnergyDrainerElectrostaticDispersion<double>),{1}),", OFFSET, value);
                    }

                }
                #endregion
                #region Energy Injectors
                else if (string.Equals("EngineeringEquipment", moduleMetagroup) && string.Equals("EnergyInjectors", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(EnergyInjectorCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AmmoChargeType");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AmmunitionType<AmmunitionTypesEnum>),AmmunitionTypesEnum.EnergyInjectorCharges),", OFFSET);
                    }
                    index = Array.IndexOf(modulesHeaders, "AmmoChargeCapacity");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AmmoCapacity<double>),{1}),", OFFSET, value);
                    }

                }
                #endregion
                #region Energy Neutralizers
                else if (string.Equals("EngineeringEquipment", moduleMetagroup) && string.Equals("EnergyNeutralizers", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(EnergyNeutralizerCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "OptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(EnergyNeutralizerOptimal<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ElectrostaticDispersion");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(EnergyNeutralizerElectrostaticDispersion<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "NeutralizedEnergy");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(EnergyNeutralizerNeutralizedEnergy<double>),{1}),", OFFSET, value);
                    }

                }
                #endregion
                #region Energy Transferers
                else if (string.Equals("EngineeringEquipment", moduleMetagroup) && string.Equals("EnergyTransferers", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(EnergyTransfererCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "OptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(EnergyTransfererOptimal<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "TransferedEnergy");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(EnergyTransfererTransferedEnergy<double>),{1}),", OFFSET, value);
                    }
                }
                #endregion
                #region ERP
                else if (string.Equals("EngineeringEquipment", moduleMetagroup) && string.Equals("ERP", moduleGroup, StringComparison.InvariantCultureIgnoreCase))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ChemicalDamageRecovery");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ChemicalDamageRecovery<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "KineticDamageRecovery");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(KineticDamageRecovery<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "SeismicDamageRecovery");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(SeismicDamageRecovery<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "ThermalDamageRecovery");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ThermalDamageRecovery<double>),{1}),", OFFSET, percent);
                    }

                }
                #endregion
                #region Evasive Modules
                else if (string.Equals("EngineeringEquipment", moduleMetagroup) && string.Equals("EvasiveModules", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "DemobilizerResistance");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.DemobilizerResistance, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Demobilizer resistance\" }},", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "SurfaceHitSize");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.SurfaceHitSize, {1} ){{ Unit = UnitsEnum.Meters, DisplayName = \"Surface hit size\" }},", OFFSET, value);
                    }

                }
                #endregion
                #endregion

                #region Industrial Modules
                #region Geoscanners
                else if (string.Equals("Industrial", moduleMetagroup) && string.Equals("Geoscanners", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture,"{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(GeoscannerCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "GeoscannerAccuracy");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(GeoscannerAccuracy<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "AmmoChargeType");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AmmunitionType<AmmunitionTypesEnum>),AmmunitionTypesEnum.GeoscannerCharges),", OFFSET);
                    }
                    index = Array.IndexOf(modulesHeaders, "AmmoChargeCapacity");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AmmoCapacity<double>),{1}),", OFFSET, value);
                    } 
                }
                #endregion
                #region Harvester Modules
                else if (string.Equals("Industrial", moduleMetagroup) && string.Equals("HarvesterModules", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture,"{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(HarvesterCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "OptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(HarvesterOptimal<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AmmoChargeType");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AmmunitionType<AmmunitionTypesEnum>),AmmunitionTypesEnum.HarvesterCharges),", OFFSET);
                    }
                    index = Array.IndexOf(modulesHeaders, "AmmoChargeCapacity");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AmmoCapacity<double>),{1}),", OFFSET, value);
                    } 
                }
                #endregion
                #region Industrial Tunings
                else if (string.Equals("Industrial", moduleMetagroup) && string.Equals("IndustrialTunings", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture,"{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "HarvestedAmountIncrease");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture,"{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.HarvestedAmount, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Harvested amount\"  }},", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "MinedAmountIncrease");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture,"{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.MinedAmount, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Mined amount\"  }},", OFFSET, percent);
                    }
                       
                }
                #endregion
                #region Miner Modules
                else if (string.Equals("Industrial", moduleMetagroup) && string.Equals("MinerModules", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture,"{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(MinerCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "OptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(MinerOptimal<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AmmoChargeType");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AmmunitionType<AmmunitionTypesEnum>),AmmunitionTypesEnum.MinerCharges),", OFFSET);
                    }
                    index = Array.IndexOf(modulesHeaders, "AmmoChargeCapacity");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AmmoCapacity<double>),{1}),", OFFSET, value);
                    } 
                }
                #endregion
                #endregion

                #region NexusModules
                #region Armor
                else if (string.Equals("NexusModules", moduleMetagroup) && string.Equals("NexusModuleArmor", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "DefaultEffectRadius");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRadius<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "EffectRangeModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRangeModification<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "ArmorModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleArmorModification<double>),{1}),", OFFSET, percent);
                    }

                }
                #endregion
                #region Assault
                else if (string.Equals("NexusModules", moduleMetagroup) && string.Equals("NexusModuleAssault", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "DefaultEffectRadius");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRadius<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "EffectRangeModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRangeModification<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "WeaponCycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleWeaponCycleTime<double>),{1}),", OFFSET, percent);
                    }

                }
                #endregion
                #region CriticalHit
                else if (string.Equals("NexusModules", moduleMetagroup) && string.Equals("NexusModuleCriticalHit", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "DefaultEffectRadius");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRadius<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "EffectRangeModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRangeModification<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "CriticalHitChanceModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleCriticalHitChanceModification<double>),{1}),", OFFSET, percent);
                    }
                }
                #endregion
                #region Evasive
                else if (string.Equals("NexusModules", moduleMetagroup) && string.Equals("NexusModuleEvasive", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "DefaultEffectRadius");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRadius<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "EffectRangeModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRangeModification<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "SurfaceHitSizeModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleSurfaceHitSizeModification<double>),{1}),", OFFSET, value);
                    }
                }
                #endregion
                #region EW
                else if (string.Equals("NexusModules", moduleMetagroup) && string.Equals("NexusModuleEw", moduleGroup, StringComparison.InvariantCultureIgnoreCase))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "DefaultEffectRadius");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRadius<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "EffectRangeModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRangeModification<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "EwModuleOptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEwModuleOptimalRange<double>),{1}),", OFFSET, percent);
                    }
                }
                #endregion
                #region Farlock
                else if (string.Equals("NexusModules", moduleMetagroup) && string.Equals("NexusModuleFarlock", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "DefaultEffectRadius");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRadius<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "EffectRangeModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRangeModification<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "LockingRangeModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleLockingRangeModification<double>),{1}),", OFFSET, percent);
                    }
                }
                #endregion
                #region Fast Extractor
                else if (string.Equals("NexusModules", moduleMetagroup) && string.Equals("NexusModuleFastExtractor", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "DefaultEffectRadius");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRadius<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "EffectRangeModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRangeModification<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "IndustrialModuleCycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleIndustrialModuleCycleTime<double>),{1}),", OFFSET, percent);
                    }
                }
                #endregion
                #region Industrial
                else if (string.Equals("NexusModules", moduleMetagroup) && string.Equals("NexusModuleIndustrial", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "DefaultEffectRadius");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRadius<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "EffectRangeModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRangeModification<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "IndustrialModuleAccumulatorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleIndustrialModuleAccumulatorUsage<double>),{1}),", OFFSET, percent);
                    }

                }
                #endregion
                #region Lock Booster
                else if (string.Equals("NexusModules", moduleMetagroup) && string.Equals("NexusModuleLockBooster", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "DefaultEffectRadius");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRadius<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "EffectRangeModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRangeModification<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "LockingTimeModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleLockingTimeModification<double>),{1}),", OFFSET, percent);
                    }
                }
                #endregion
                #region Recharger
                else if (string.Equals("NexusModules", moduleMetagroup) && string.Equals("NexusModuleRecharger", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "DefaultEffectRadius");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRadius<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "EffectRangeModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRangeModification<double>),{1}),", OFFSET, percent);
                    }

                    index = Array.IndexOf(modulesHeaders, "AccumulatorRechargeTimeModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleAccumulatorRechargeTimeModification<double>),{1}),", OFFSET, percent);
                    }
                }
                #endregion
                #region Repairer
                else if (string.Equals("NexusModules", moduleMetagroup) && string.Equals("NexusModuleRepairer", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "DefaultEffectRadius");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRadius<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "EffectRangeModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRangeModification<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "ArmorRepairAmountModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleArmorRepairAmountModification<double>),{1}),", OFFSET, percent);
                    }
                }
                #endregion
                #region Shield
                else if (string.Equals("NexusModules", moduleMetagroup) && string.Equals("NexusModuleShield", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "DefaultEffectRadius");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRadius<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "EffectRangeModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRangeModification<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "ShieldAbsorptionModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleShieldAbsorptionModification<double>),{1}),", OFFSET, percent);
                    }
                }
                #endregion
                #region Velocity
                else if (string.Equals("NexusModules", moduleMetagroup) && string.Equals("NexusModuleVelocity", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "DefaultEffectRadius");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRadius<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "EffectRangeModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleEffectRangeModification<double>),{1}),", OFFSET, percent);
                    }
                    index = Array.IndexOf(modulesHeaders, "TopSpeedModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(NexusModuleTopSpeedModification<double>),{1}),", OFFSET, percent);
                    }
                }
                #endregion
                #endregion

                #region Shield
                #region Shield Generators
                else if (string.Equals("Shield", moduleMetagroup) && string.Equals("ShieldGenerators", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ShieldCpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ShieldReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ShieldCycleTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AbsorptionRatio");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ShieldAbsorptionRatio<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ShieldRadius");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ShieldRadius<double>),{1}),", OFFSET, value);
                    }
                }
                #endregion
                #region Shield Hardeners
                else if (string.Equals("Shield", moduleMetagroup) && string.Equals("ShieldHardeners", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ShieldHardenerCpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ShieldHardenerReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ShieldAbsorption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.ShieldAbsorptionRatio, {1} ){{ Unit = UnitsEnum.Percentage,  DisplayName = \"Shield absorption\" }},", OFFSET, percent);
                    }
                }
                #endregion
                #endregion

                #region Weapons
                #region Firearms
                else if (string.Equals("Weapons", moduleMetagroup) && string.Equals("Firearms", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(WeaponCpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(WeaponReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(WeaponAccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AmmoChargeType");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        //var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AmmunitionType<AmmunitionTypesEnum>),AmmunitionTypesEnum.{1}),", OFFSET, NormalizeString(values[index]));
                    }
                    index = Array.IndexOf(modulesHeaders, "AmmoChargeCapacity");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AmmoCapacity<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof({2}FirearmCycleTime<double>),{1}),", OFFSET, value, moduleSize);
                    }
                    index = Array.IndexOf(modulesHeaders, "OptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof({2}FirearmOptimal<double>),{1}),", OFFSET, value, moduleSize);
                    }
                    index = Array.IndexOf(modulesHeaders, "Falloff");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof({2}FirearmFalloff<double>),{1}),", OFFSET, value, moduleSize);
                    }
                    index = Array.IndexOf(modulesHeaders, "Damage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof({2}FirearmDamage<double>),{1}),", OFFSET, percent, moduleSize);
                    }
                    index = Array.IndexOf(modulesHeaders, "HitDispersion");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof({2}FirearmHitDispersion<double>),{1}),", OFFSET, value, moduleSize);
                    }
                }
                #endregion
                #region Lasers
                else if (string.Equals("Weapons", moduleMetagroup) && string.Equals("Lasers", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(WeaponCpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(WeaponReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(WeaponAccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AmmoChargeType");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        //var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AmmunitionType<AmmunitionTypesEnum>),AmmunitionTypesEnum.{1}),", OFFSET, NormalizeString(values[index]));
                    }
                    index = Array.IndexOf(modulesHeaders, "AmmoChargeCapacity");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AmmoCapacity<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof({2}LaserCycleTime<double>),{1}),", OFFSET, value, moduleSize);
                    }
                    index = Array.IndexOf(modulesHeaders, "OptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof({2}LaserOptimal<double>),{1}),", OFFSET, value, moduleSize);
                    }
                    index = Array.IndexOf(modulesHeaders, "Falloff");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof({2}LaserFalloff<double>),{1}),", OFFSET, value, moduleSize);
                    }
                    index = Array.IndexOf(modulesHeaders, "Damage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof({2}LaserDamage<double>),{1}),", OFFSET, percent, moduleSize);
                    }
                    index = Array.IndexOf(modulesHeaders, "HitDispersion");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof({2}LaserHitDispersion<double>),{1}),", OFFSET, value, moduleSize);
                    }
                }
                #endregion
                #region Magnetic Weapons
                else if (string.Equals("Weapons", moduleMetagroup) && string.Equals("MagneticWeapons", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(WeaponCpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(WeaponReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(WeaponAccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AmmoChargeType");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        //var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AmmunitionType<AmmunitionTypesEnum>),AmmunitionTypesEnum.{1}),", OFFSET, NormalizeString(values[index]));
                    }
                    index = Array.IndexOf(modulesHeaders, "AmmoChargeCapacity");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AmmoCapacity<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof({2}MagneticWeaponCycleTime<double>),{1}),", OFFSET, value, moduleSize);
                    }
                    index = Array.IndexOf(modulesHeaders, "OptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof({2}MagneticWeaponOptimal<double>),{1}),", OFFSET, value, moduleSize);
                    }
                    index = Array.IndexOf(modulesHeaders, "Falloff");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof({2}MagneticWeaponFalloff<double>),{1}),", OFFSET, value, moduleSize);
                    }
                    index = Array.IndexOf(modulesHeaders, "Damage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof({2}MagneticWeaponDamage<double>),{1}),", OFFSET, percent, moduleSize);
                    }
                    index = Array.IndexOf(modulesHeaders, "HitDispersion");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof({2}MagneticWeaponHitDispersion<double>),{1}),", OFFSET, value, moduleSize);
                    }
                }
                #endregion
                #region Missile Launchers
                else if (string.Equals("Weapons", moduleMetagroup) && string.Equals("MissileLaunchers", moduleGroup))
                {
                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(WeaponCpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(WeaponReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AccumulatorConsumption");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(WeaponAccumulatorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "AmmoChargeType");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        //var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AmmunitionType<AmmunitionTypesEnum>),AmmunitionTypesEnum.{1}),", OFFSET, NormalizeString(values[index]));
                    }
                    index = Array.IndexOf(modulesHeaders, "AmmoChargeCapacity");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(AmmoCapacity<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "CycleTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof({2}MissileLauncherCycleTime<double>),{1}),", OFFSET, value, moduleSize);
                    }
                    index = Array.IndexOf(modulesHeaders, "HitDispersion");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof({2}MissileLauncherHitDispersion<double>),{1}),", OFFSET, value, moduleSize);
                    }
                    index = Array.IndexOf(modulesHeaders, "Damage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) ;
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(MissileLauncherDamage<double>),{1}),", OFFSET, percent);
                    }
                    // Base optimal range (modified by ammo)
                    featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(MissileLauncherOptimal<double>),{1}),", OFFSET, 0);

                    index = Array.IndexOf(modulesHeaders, "MissileOptimalRangeModification");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Ammo, FeaturesEnum.MissileOptimal, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Missile optimal range\" }},", OFFSET, percent);
                    }
                }
                #endregion
                #region Weapon Tunings
                else if (string.Equals("Weapons", moduleMetagroup) && string.Equals("WeaponTunings", moduleGroup))
                {

                    index = Array.IndexOf(modulesHeaders, "CpuUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(CpuUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "ReactorUsage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ReactorUsage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(modulesHeaders, "Mass");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ModuleMass<double>),{1}),", OFFSET, value);
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.RobotMass, {1} ){{ IsVisible = false }},", OFFSET, value);
                    }


                    if (string.Equals("WeaponStabilizers", moduleClass))
                    {
                        index = Array.IndexOf(modulesHeaders, "DemobilizerResistance");
                        if (index != -1 && !string.IsNullOrEmpty(values[index]))
                        {
                            var value = RemoveUnit(values[index]);
                            double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.DemobilizerResistance, {1:0.00} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Demobilizer resistance\" }},", OFFSET, percent);
                        }
                        index = Array.IndexOf(modulesHeaders, "HitDispersion");
                        if (index != -1 && !string.IsNullOrEmpty(values[index]))
                        {
                            var value = RemoveUnit(values[index]);
                            double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;

                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.SmallMagneticWeaponHitDispersion, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Small Magnetic weapon hit dispersion\" }},", OFFSET, percent);
                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.MediumMagneticWeaponHitDispersion, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Medium Magnetic weapon hit dispersion\" }},", OFFSET, percent);

                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.SmallFirearmHitDispersion, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Small Firearm hit dispersion\" }},", OFFSET, percent);
                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.MediumFirearmHitDispersion, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Medium Firearm hit dispersion\" }},", OFFSET, percent);

                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.SmallLaserHitDispersion, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Small Laser hit dispersion\" }},", OFFSET, percent);
                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.MediumLaserHitDispersion, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Medium Laser hit dispersion\" }},", OFFSET, percent);
                        }
                        index = Array.IndexOf(modulesHeaders, "ExplosionSize");
                        if (index != -1 && !string.IsNullOrEmpty(values[index]))
                        {
                            var value = RemoveUnit(values[index]);
                            double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Ammo, FeaturesEnum.AmmunitionExplosionSize, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Explosion size\" }},", OFFSET, percent);
                        }
                    }
                    else if (string.Equals("MissileLaunchers", moduleClass))
                    {
                        index = Array.IndexOf(modulesHeaders, "MissileLauncherCycleTime");
                        if (index != -1 && !string.IsNullOrEmpty(values[index]))
                        {
                            var value = RemoveUnit(values[index]);
                            double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;

                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.SmallMissileLauncherCycleTime, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Small missile launcher cycle time\" }},", OFFSET, percent);
                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.MediumMissileLauncherCycleTime, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Medium missile launcher cycle time\" }},", OFFSET, percent);
                        }
                        index = Array.IndexOf(modulesHeaders, "Damage");
                        if (index != -1 && !string.IsNullOrEmpty(values[index]))
                        {
                            var value = RemoveUnit(values[index]);
                            double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;

                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.SmallMissileDamage, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Small missile damage\" }},", OFFSET, percent);
                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.MediumMissileDamage, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Medium missile damage\" }},", OFFSET, percent);
                        }
                        index = Array.IndexOf(modulesHeaders, "CriticalHitChance");
                        if (index != -1 && !string.IsNullOrEmpty(values[index]))
                        {
                            var value = RemoveUnit(values[index]);
                            double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.CriticalHitChance, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Critical hit chance\" }},", OFFSET, percent);
                        }

                        index = Array.IndexOf(modulesHeaders, "CriticalHitChanceModification");
                        if (index != -1 && !string.IsNullOrEmpty(values[index]))
                        {
                            var value = RemoveUnit(values[index]);
                            double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.CriticalHitChance, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Critical hit chance\" }},", OFFSET, percent);
                        }
                    }
                    else
                    {

                        index = Array.IndexOf(modulesHeaders, "CycleTime");
                        if (index != -1 && !string.IsNullOrEmpty(values[index]))
                        {
                            var value = RemoveUnit(values[index]);
                            double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;

                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.Small{2}CycleTime, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Small {2} cycle time\" }},", OFFSET, percent, moduleClass.Substring(0, moduleClass.Length - 1));
                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.Medium{2}CycleTime, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Medium {2} cycle time\" }},", OFFSET, percent, moduleClass.Substring(0, moduleClass.Length - 1));
                        }
                        index = Array.IndexOf(modulesHeaders, "Damage");
                        if (index != -1 && !string.IsNullOrEmpty(values[index]))
                        {
                            var value = RemoveUnit(values[index]);
                            double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;

                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.Small{2}Damage, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Small {2} damage\" }},", OFFSET, percent, moduleClass.Substring(0, moduleClass.Length - 1));
                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.Medium{2}Damage, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Medium {2} damage\" }},", OFFSET, percent, moduleClass.Substring(0, moduleClass.Length - 1));
                        }

                        index = Array.IndexOf(modulesHeaders, "CriticalHitChance");
                        if (index != -1 && !string.IsNullOrEmpty(values[index]))
                        {
                            var value = RemoveUnit(values[index]);
                            double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.CriticalHitChance, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Critical hit chance\" }},", OFFSET, percent);
                        }

                        index = Array.IndexOf(modulesHeaders, "CriticalHitChanceModification");
                        if (index != -1 && !string.IsNullOrEmpty(values[index]))
                        {
                            var value = RemoveUnit(values[index]);
                            double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                            modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Robot, FeaturesEnum.CriticalHitChance, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName =\"Critical hit chance\" }},", OFFSET, percent);
                        }

                    }

                }
                #endregion
                #endregion

                classBuilder
                    .Append(MODULE_CLASS)
                    .Replace("<METAGROUP>", moduleMetagroup ?? "NotDefined")
                    .Replace("<GROUP>", moduleGroup ?? "NotDefined")
                    .Replace("<SIZE>", moduleSize ?? "Small")
                    .Replace("<MODULENAME>", moduleName)
                    .Replace("<MODULENAMELONG>", moduleDescription)
                    .Replace("<TECH>", techLevel ?? "NotDefined")
                    .Replace("<ACTIVATION>", activation ?? "NotDefined")
                    .Replace("<SLOTGROUP>", slotGroup ?? "NotDefined")
                    .Replace("<SLOTTYPE>", slotType ?? "NotDefined")
                    .Replace("<DATE>", DateTime.Now.ToString())
                    .Replace("<HEADER>", headerBuilder.ToString())
                    .Replace("<FEATURES>", featuresBuilder.ToString())
                    .Replace("<MODIFIERS>", modifiersBuilder.ToString());

                // Creating generated cs file path
                string path = null;
                path += Path.DirectorySeparatorChar + moduleMetagroup + Path.DirectorySeparatorChar + moduleGroup;
                if(!string.IsNullOrEmpty(moduleClass))
                    path += Path.DirectorySeparatorChar + moduleClass;
                if (!string.IsNullOrEmpty(moduleSize))
                    path += Path.DirectorySeparatorChar + moduleSize;
                path = outdir + path;

                // creating generated file directory if needed
                if (!Directory.Exists(path))
                    Directory.CreateDirectory(path);

                // final full generated file path
                path = Path.Combine(path, moduleName + ".cs");

                File.Delete(path);
                File.WriteAllText(path, classBuilder.ToString(), Encoding.UTF8);
            }
            
            // Closing xml file tree
            if(!string.IsNullOrEmpty(lastSize))
                xmlTreeBuilder.AppendFormat("</{0}>", lastSize);
            if(!string.IsNullOrEmpty(lastClass))
                xmlTreeBuilder.AppendFormat("</{0}>", lastClass);   
            if(!string.IsNullOrEmpty(lastGroup))
                xmlTreeBuilder.AppendFormat("</{0}>", lastGroup);
            if(!string.IsNullOrEmpty(lastMetagroup))
                xmlTreeBuilder.AppendFormat("</{0}>", lastMetagroup);

            xmlTreeBuilder.Append("</modules>");

            // generating xml modules file
            File.WriteAllText(outdir + "\\modules.xml" , xmlTreeBuilder.ToString(), Encoding.UTF8);


            Debug.WriteLine("Replaced descriptions: {0}/{1}", replacedcount, itemsCount);
        }

        static void ParseAmmo(string file, string outdir)
        {
            if (string.IsNullOrEmpty(file) || string.IsNullOrEmpty(outdir)) return;

            if (!Directory.Exists(outdir))
                Directory.CreateDirectory(outdir);

            var classBuilder = new StringBuilder();
            var featuresBuilder = new StringBuilder();
            var modifiersBuilder = new StringBuilder();
            var headerBuilder = new StringBuilder();

            // Initializing xml modules file tree
            var xmlTreeBuilder = new StringBuilder();
            xmlTreeBuilder.Append("<?xml version=\"1.0\" encoding=\"utf-8\"?><ammunitions>");

            string lastGroup = null;
            string lastType = null;
            string lastSize = null;

            // reading csv file content
            var lines = File.ReadAllLines(file, Encoding.UTF8);

            int replacedcount = 0;
            int itemsCount = 0;


            for (int l = 1; l < lines.Length; l++) // skiping header line
            {
                if (string.IsNullOrEmpty(lines[l])) continue;

                itemsCount++;

                classBuilder.Clear();
                featuresBuilder.Clear();
                modifiersBuilder.Clear();
                headerBuilder.Clear();

                string ammoGroup = null;
                string ammoType = null;
                string ammoSize = null;
                string ammoName = null;
                string ammoDescription = null;
                

                // Generating file header
                var values = lines[l].Split(';');
                for (int i = 0; i < values.Length; i++)
                {
                    if (string.IsNullOrEmpty(values[i])) continue;
                    headerBuilder.AppendFormat("\r\n\t\t{0,-30} = {1}", ammosHeaders[i], values[i]);
                }

                int index;

                index = Array.IndexOf(ammosHeaders, "Group");
                if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    ammoGroup = values[index].Replace("InterferenceEmitters", "InterferenceEmitterCharges");

                index = Array.IndexOf(ammosHeaders, "Size");
                if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    ammoSize = values[index];

                index = Array.IndexOf(ammosHeaders, "Type");
                if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    ammoType = values[index];

                index = Array.IndexOf(ammosHeaders, "Name");
                if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    ammoDescription = values[index];


                ammoDescription = ammoDescription
                    .Replace("flechette", "'Flechette'")
                    .Replace("apocalypse", "'Apocalypse'")
                    .Replace("crypto", "'Crypto'")
                    .Replace("smite", "'Smite'")
                    .Replace("magnedart", "'Magnedart'")
                    .Replace("epriton", "(epriton)")
                    .Replace("hdt", "(hdt)")
                    .Replace("imentium", "(imentium)")
                    .Replace("liquizit", "(liquizit)")
                    .Replace("stermonit", "(stermonit)")
                    .Replace("titan ore", "(titan ore)")
                    .Trim();

                bool found = false;
                var dicEnu = _descriptions.GetEnumerator();
                while (dicEnu.MoveNext())
                {
                    if (string.Equals(dicEnu.Current.Value, ammoDescription, StringComparison.InvariantCultureIgnoreCase))
                    {
                        ammoDescription = dicEnu.Current.Value;
                        replacedcount++;
                        found = true;
                        break;
                    }
                }

                if (!found)
                    Debug.WriteLine(ammoDescription);

                var temp = ammoDescription.Replace("#", "").Replace(".", "").Replace("'", "").Replace("-", " ").Replace("(","").Replace(")","").TrimStart();

                // remove numbers from starting position
                while (char.IsNumber(temp.ToCharArray()[0]) || char.IsWhiteSpace(temp.ToCharArray()[0]))
                    temp = temp.Substring(1);

                ammoName = NormalizeString(temp);


                #region XML modules tree

                if (!string.Equals(lastSize, ammoSize))
                {
                    if (!string.IsNullOrEmpty(lastSize))
                        xmlTreeBuilder.AppendFormat("</{0}>", lastSize);
                }
                if (!string.Equals(lastType, ammoType))
                {
                    if (!string.IsNullOrEmpty(lastType))
                        xmlTreeBuilder.AppendFormat("</{0}>", lastType);
                }
                if (!string.Equals(lastGroup, ammoGroup))
                {
                    if (!string.IsNullOrEmpty(lastGroup))
                        xmlTreeBuilder.AppendFormat("</{0}>", lastGroup);
                }

                if (!string.IsNullOrEmpty(ammoGroup) && !string.Equals(lastGroup, ammoGroup))
                    xmlTreeBuilder.AppendFormat("<{0}>", ammoGroup);

                if (!string.IsNullOrEmpty(ammoType) && !string.Equals(lastType, ammoType))
                    xmlTreeBuilder.AppendFormat("<{0}>", ammoType);

                if (!string.IsNullOrEmpty(ammoSize) && !string.Equals(lastSize, ammoSize))
                    xmlTreeBuilder.AppendFormat("<{0}>", ammoSize);

                xmlTreeBuilder.AppendFormat("<ammunition type=\"{0}\">{1}</ammunition>", ammoName, ammoDescription);

                lastGroup = ammoGroup;
                lastType = ammoType;
                lastSize = ammoSize;

                #endregion

                #region Ammunitions

                #region Slugs

                if (string.Equals("Slugs", ammoGroup))
                {

                    ammoType = string.Format("{0}Slugs",ammoSize);

                    index = Array.IndexOf(ammosHeaders, "KineticDamage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(KineticDamage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(ammosHeaders, "SeismicDamage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(SeismicDamage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(ammosHeaders, "ChemicalDamage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ChemicalDamage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(ammosHeaders, "ThermalDamage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ThermalDamage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(ammosHeaders, "OptimalRangeModifier");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture)/100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.{2}MagneticWeaponOptimal, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Optimal\" }},", OFFSET, percent, ammoSize);
                    }
                    
                }

                #endregion

                #region Bullets

                else if (string.Equals("Bullets", ammoGroup))
                {
                    ammoType = string.Format("{0}Bullets", ammoSize);

                    index = Array.IndexOf(ammosHeaders, "KineticDamage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(KineticDamage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(ammosHeaders, "SeismicDamage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(SeismicDamage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(ammosHeaders, "ChemicalDamage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ChemicalDamage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(ammosHeaders, "ThermalDamage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ThermalDamage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(ammosHeaders, "OptimalRangeModifier");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture)/100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.{2}FirearmOptimal, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Optimal\" }},", OFFSET, percent, ammoSize);
                    }
                    index = Array.IndexOf(ammosHeaders, "FalloffModifier");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) /100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.{2}FirearmFalloff, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Falloff\" }},", OFFSET, percent, ammoSize);
                    }
                }

                #endregion

                #region Energy cells

                else if (string.Equals("EnergyCells", ammoGroup))
                {
                    ammoType = string.Format("{0}EnergyCells", ammoSize);

                    index = Array.IndexOf(ammosHeaders, "KineticDamage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(KineticDamage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(ammosHeaders, "SeismicDamage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(SeismicDamage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(ammosHeaders, "ChemicalDamage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ChemicalDamage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(ammosHeaders, "ThermalDamage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ThermalDamage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(ammosHeaders, "OptimalRangeModifier");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.{2}LaserOptimal, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Optimal\" }},", OFFSET, percent, ammoSize);
                    }
                    index = Array.IndexOf(ammosHeaders, "FalloffModifier");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        double percent = double.Parse(value, CultureInfo.InvariantCulture) / 100;
                        modifiersBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new Modifier( FeatureTypesEnum.Module, FeaturesEnum.{2}LaserFalloff, {1} ){{ Unit = UnitsEnum.Percentage, DisplayName = \"Falloff\" }},", OFFSET, percent, ammoSize);
                    }

                }

                #endregion

                #region Missiles

                else if (string.Equals("Missiles", ammoGroup))
                {
                    ammoType = string.Format("{0}Missiles", ammoSize);

                    index = Array.IndexOf(ammosHeaders, "KineticDamage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(KineticDamage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(ammosHeaders, "SeismicDamage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(SeismicDamage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(ammosHeaders, "ChemicalDamage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ChemicalDamage<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(ammosHeaders, "ThermalDamage");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ThermalDamage<double>),{1}),", OFFSET, value);
                    }

                    index = Array.IndexOf(ammosHeaders, "ExplosionSize");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof({2}MissileExplosionSize<double>),{1}),", OFFSET, value, ammoSize);
                    }

                    index = Array.IndexOf(ammosHeaders, "OptimalRange");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(MissileOptimal<double>),{1}),", OFFSET, value);
                    }
                }

                #endregion

                #region EnergyInjectorCharges

                else if (string.Equals("EnergyInjectorCharges", ammoGroup))
                {
                    ammoType = ammoGroup;

                    index = Array.IndexOf(ammosHeaders, "AddedEnergy");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(InjectedAccumulatorAmount<double>),{1}),", OFFSET, value);
                    }
                }

                #endregion

                #region GeoscannerCharges

                else if (string.Equals("GeoscannerCharges", ammoGroup))
                {
                    ammoType = ammoGroup;

                    index = Array.IndexOf(ammosHeaders, "RadiusOfScannedArea");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ScanAreaRadius<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(ammosHeaders, "ScannedAreaRadius");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ScanAreaRadius<double>),{1}),", OFFSET, value);
                    }
                }

                #endregion

                #region InterferenceEmitters

                else if (string.Equals("InterferenceEmitterCharges", ammoGroup))
                {
                    ammoType = ammoGroup;

                    index = Array.IndexOf(ammosHeaders, "TotalOperationalTime");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(OperationalTime<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(ammosHeaders, "Armor");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(ArmorAmount<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(ammosHeaders, "SurfaceHitSize");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(SurfaceHitSize<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(ammosHeaders, "InterferenceEmission");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(InterferenceEmission<double>),{1}),", OFFSET, value);
                    }
                    index = Array.IndexOf(ammosHeaders, "InterferenceRadius");
                    if (index != -1 && !string.IsNullOrEmpty(values[index]))
                    {
                        var value = RemoveUnit(values[index]);
                        featuresBuilder.AppendFormat(CultureInfo.InvariantCulture, "{0}new LazyFeature(typeof(InterferenceRadius<double>),{1}),", OFFSET, value);
                    }
                }

                #endregion

                #region HarvesterCharges

                else if (string.Equals("HarvesterCharges", ammoGroup))
                {
                    ammoType = ammoGroup;
                }

                #endregion

                #region MinerCharges

                else if (string.Equals("MinerCharges", ammoGroup))
                {
                    ammoType = ammoGroup;
                }

                #endregion


                #endregion

                classBuilder
                    .Append(AMMO_CLASS)
                    .Replace("<GROUP>", ammoGroup ?? "NotDefined")
                    .Replace("<TYPE>", ammoType ?? "NotDefined")
                    .Replace("<SIZE>", ammoSize ?? "Small")
                    .Replace("<CLASS>", ammoName)
                    .Replace("<AMMO>", ammoDescription)
                    .Replace("<DATE>", DateTime.Now.ToString())
                    .Replace("<HEADER>", headerBuilder.ToString())
                    .Replace("<FEATURES>", featuresBuilder.ToString())
                    .Replace("<MODIFIERS>", modifiersBuilder.ToString());

                // Creating generated cs file path
                string path = null;
                path += Path.DirectorySeparatorChar + ammoGroup;

                if (!string.IsNullOrEmpty(ammoSize))
                    path += Path.DirectorySeparatorChar + ammoSize;
                else if (!string.IsNullOrEmpty(ammoType) && !string.Equals(ammoType,ammoGroup))
                    path += Path.DirectorySeparatorChar + ammoType;
                
                path = outdir + path;

                // creating generated file directory if needed
                if (!Directory.Exists(path))
                    Directory.CreateDirectory(path);

                // final full generated file path
                path = Path.Combine(path, ammoName + ".cs");

                File.Delete(path);
                File.WriteAllText(path, classBuilder.ToString(), Encoding.UTF8);
            }


            // Closing xml file tree
            if (!string.IsNullOrEmpty(lastSize))
                xmlTreeBuilder.AppendFormat("</{0}>", lastSize);
            if (!string.IsNullOrEmpty(lastType))
                xmlTreeBuilder.AppendFormat("</{0}>", lastType);
            if (!string.IsNullOrEmpty(lastGroup))
                xmlTreeBuilder.AppendFormat("</{0}>", lastGroup);

            xmlTreeBuilder.Append("</ammunitions>");

            // generating xml file
            File.WriteAllText(outdir + "\\ammunitions.xml", xmlTreeBuilder.ToString(), Encoding.UTF8);


            Debug.WriteLine("Replaced descriptions: {0}/{1}", replacedcount, itemsCount);
        }

        static string NormalizeString(string value)
        {
            if (string.IsNullOrEmpty(value)) return null;

            var sb = new StringBuilder();

            var parts = value.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries);

            for (int i = 0; i < parts.Length; i++)
                sb.AppendFormat(CultureInfo.InvariantCulture,"{0}{1}", parts[i].Substring(0, 1).ToUpper(), parts[i].Substring(1).ToLower());

            return sb.ToString();
        }
        
        static string RemoveUnit(string value)
        {
            return value.Split(' ')[0].Trim();
        }

        static void ParseModulesCsvFiles(string topdir)
        {
            var csvfiles = Directory.GetFiles(topdir + "\\Modules", "*.csv", SearchOption.AllDirectories);

            File.Delete(".\\modules.csv");
            var writer = new StreamWriter(".\\modules.csv", false, Encoding.UTF8);

            writer.WriteLine(string.Join(";", modulesHeaders));

            foreach (var csvfile in csvfiles)
            {
                string meta = null;
                string group = null;
                string modulename = null;
                string size = null;
                string moduleclass = null;

                string path = Path.GetDirectoryName(csvfile);
                if (string.IsNullOrEmpty(path)) continue;

                var pathParts = path.Split(new char[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);

                meta = NormalizeString(pathParts[5]);
                group = NormalizeString(pathParts[6]);
                size = pathParts.Length > 7 ? NormalizeString(pathParts[7]) : null;
                moduleclass = pathParts.Length > 7 ? NormalizeString(pathParts[7]) : null;

                if (string.Equals(moduleclass, "Small", StringComparison.InvariantCultureIgnoreCase) ||
                    string.Equals(moduleclass, "Medium", StringComparison.InvariantCultureIgnoreCase))
                    moduleclass = null;
                else
                    size = null;

                var values = new string[modulesHeaders.Length];

                values[0] = meta;
                values[1] = group;
                values[2] = moduleclass;
                values[3] = size;
                
                var tempName = Path.GetFileNameWithoutExtension(csvfile).Replace("iteminfo_", "").Replace("iteminfo-","").Replace("__", "_");
                modulename = tempName.Substring(0, tempName.IndexOf("-2011")).Replace("_", " ");

                values[4] = modulename;
                
                var lines = File.ReadAllLines(csvfile);
                for (int i = 0; i < lines.Length; i++)
                {
                    var parts = lines[i].Replace("\"", "").Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                    if (parts.Length < 2) continue;

                    var key = NormalizeString(parts[0])
                        .Replace("Ammo/chargeType", "AmmoChargeType")
                        .Replace("Ammo/chargeCapacity", "AmmoChargeCapacity");

                    var value = parts[1];

                    var headerIndex = Array.IndexOf(modulesHeaders, key);
                    if (headerIndex == -1) continue;

                    values[headerIndex] = value;

                }

                writer.WriteLine(string.Join(";", values));
            }
            writer.Flush();
            writer.Close();
            writer.Dispose();
        }

        static void ParseAmmoCsvFiles(string dir)
        {
            if(string.IsNullOrEmpty(dir)) return;

            var csvfiles = Directory.GetFiles(dir + "\\Ammunitions", "*.csv", SearchOption.AllDirectories);

            File.Delete(".\\Ammunitions.csv");
            using (var writer = new StreamWriter(".\\Ammunitions.csv", false, Encoding.UTF8))
            {
                writer.WriteLine(string.Join(";", ammosHeaders));

                foreach (var csvfile in csvfiles)
                {
                    string group = null;
                    string ammoName = null;
                    string size = null;
                    string ammoType = null;

                    string path = Path.GetDirectoryName(csvfile);
                    if (string.IsNullOrEmpty(path)) continue;

                    var tempName = Path.GetFileNameWithoutExtension(csvfile).Replace("iteminfo_", "").Replace("iteminfo-", "").Replace("__", "_");
                    ammoName = tempName.Substring(0, tempName.IndexOf("-2011")).Replace("_", " ");
                    
                    var pathParts = path.Split(new char[] { Path.DirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries);

                    group = NormalizeString(pathParts[5]);
                    size = pathParts.Length > 6 ? NormalizeString(pathParts[6]) : null;

                    if (string.Equals(size, "Small", StringComparison.InvariantCultureIgnoreCase) || string.Equals(size, "Medium", StringComparison.InvariantCultureIgnoreCase))
                        ammoType = null;
                    else
                    {
                        ammoType = size;
                        size = null;
                    }

                    var values = new string[ammosHeaders.Length];

                    values[0] = group;
                    values[1] = size;
                    values[2] = ammoType;
                    values[3] = ammoName;


                    var lines = File.ReadAllLines(csvfile);
                    for (int i = 0; i < lines.Length; i++)
                    {
                        var parts = lines[i].Replace("\"", "").Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries);
                        if (parts.Length < 2) continue;

                        var key = NormalizeString(parts[0]);

                        var value = parts[1];

                        var headerIndex = Array.IndexOf(ammosHeaders, key);
                        if (headerIndex == -1) continue;

                        values[headerIndex] = value;
                    }

                    writer.WriteLine(string.Join(";", values));
                }
                writer.Flush();
                writer.Close();
            }

        }

        static string[] GetAmmosHeaders(string  dir)
        {
            var csvfiles = Directory.GetFiles(dir + "\\Ammunitions", "*.csv", SearchOption.AllDirectories);

            var headers = new List<string>();
            for (int i = 0; i < csvfiles.Length; i++)
            {
                var lines = File.ReadAllLines(csvfiles[i]);
                for (int j = 0; j < lines.Length; j++)
                {
                    var values = lines[j].Replace("\"", "").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
                    if (values.Length < 2 || string.IsNullOrEmpty(values[0]) || string.IsNullOrEmpty(values[1])) continue;

                    if (headers.Contains(values[0])) continue;

                    headers.Add(values[0]);
                }
            }
            
            headers.Sort((a, b) => string.Compare(a, b));
            return headers.ToArray();
            
        }
    }
}
